package language.advanced.generic;

import com.sun.org.apache.xalan.internal.xsltc.cmdline.Compile;
import org.apache.poi.ss.formula.functions.T;
import org.junit.Test;

import java.util.ArrayList;
import java.util.List;

//为什么需要通配符和协变
public class CovariantArrays {

    class Fruit {}
    class Apple extends Fruit {}
    class Orange extends Fruit {}

    @Test
    public void adf(){
        List<Fruit> flist = new ArrayList<>();

        flist.add(new Apple()); //符合里式替换原则
        //         flist.add(new Object());  Compile Error: can't add any type of object:
//         flist.add(new Object());
        flist.add(null); // Legal but uninteresting

        // We know it returns at least Fruit:
        Fruit f = flist.get(0);
    }


    @Test
    public void Wildcards() {
        // Wildcards allow covariance:
        List<? extends Fruit> fextend = new ArrayList<Apple>();
        //fextend.add(new Object()); //编译错误,无法add任何对象。因为无法确定<? extends Fruit>的类型
        for (Fruit fruit : fextend) {
            System.out.println(fruit);
        }//但可以用Fruit去遍历对象，因为<? extends Fruit> 至少拥有Fruit的方法

        //想要存储对象，就需要下限通配符
        List<? super Apple> fsuper = new ArrayList<Fruit>();
        fsuper.add(new Apple()); //可以add Apple对象，因为子类可以向上转型
        for (Object o : fsuper) {

        } //<? super Apple>类型不确定。所以取数据的话只能当成Object来操作
        //PECS原则 Producer Extends Consumer Super
    }


    @Test
    public void test() {
        List<Apple> apples = new ArrayList<Apple>();
        List<Orange> oranges = new ArrayList<Orange>();

//        f2(apples); // 会发生编译错误
        inspect(apples);
        inspect(oranges);
    }

    // 为什么需要通配符，实现函数参数的向上转型。
    // 限制这里参数可以是List<Apple>、List<Orange> 等一系列派生出的具体水果列表
    public void inspect(List<? extends Fruit> list) {
        for (Fruit fruit : list) {
            System.out.println(fruit);
        }  // 这个操作在当前方法的上下文是合法的。
    }

    public void f2(List<Fruit> list) {
        for (Fruit fruit : list) {
            System.out.println(fruit);
        }  // 这个操作在当前方法的上下文是合法的。
    }
}
